﻿//BasePosition.cs
//Copyright (c) 2013 StockSharp LLC, all rights reserved.
//This code module is part of StockSharp library.
//This code is licensed under the GNU GENERAL PUBLIC LICENSE Version 3.
//See the file License.txt for the license details.
//More info on: http://stocksharp.com

namespace StockSharp.BusinessEntities
{
	using System;
	using System.Collections.Generic;
	using System.ComponentModel;
	using System.Runtime.Serialization;
	using System.Xml.Serialization;

	using Ecng.ComponentModel;
	using Ecng.Serialization;

	/// <summary>
	/// Базовые класс, описывающий денежную позицию и позицию по инструменту.
	/// </summary>
	public abstract class BasePosition : NotifiableObject, IExtendableEntity, IAtomic
	{
		private const string _mainCategory = "Основные";
		private readonly TransactionManager _manager = new TransactionManager();

		/// <summary>
		/// Инициализировать <see cref="BasePosition"/>.
		/// </summary>
		protected BasePosition()
		{
		}

		private decimal _beginValue;

		/// <summary>
		/// Размер позиции на начало торговой сессии.
		/// </summary>
		[DataMember]
		[DisplayName("Начальное значение")]
		[Description("Размер позиции на начало торговой сессии.")]
		[Category(_mainCategory)]
		public decimal BeginValue
		{
			get { return _beginValue; }
			set
			{
				if (_beginValue == value)
					return;

				_beginValue = value;
				Notify("BeginValue");
			}
		}

		private decimal _currentValue;

		/// <summary>
		/// Размер позиции на текущий момент.
		/// </summary>
		[DataMember]
		[DisplayName("Текущая значение")]
		[Description("Размер позиции на текущий момент.")]
		[Category(_mainCategory)]
		public decimal CurrentValue
		{
			get { return _currentValue; }
			set
			{
				if (_currentValue == value)
					return;

				_currentValue = value;
				Notify("CurrentValue");
			}
		}

		private decimal _blockedValue;

		/// <summary>
		/// Размер позиции, зарезервированной под активные заявки.
		/// </summary>
		[DataMember]
		[DisplayName("Заблокировано")]
		[Description("Размер позиции, зарезервированной под активные заявки.")]
		[Category(_mainCategory)]
		public decimal BlockedValue
		{
			get { return _blockedValue; }
			set
			{
				if (_blockedValue == value)
					return;

				_blockedValue = value;
				Notify("BlockedValue");
			}
		}

		[field: NonSerialized]
		private IDictionary<object, object> _extensionInfo;

		/// <summary>
		/// Расширенная информация.
		/// </summary>
		/// <remarks>
		/// Необходима в случае хранения в программе дополнительной информации. Например, размер уплаченной комиссии.
		/// </remarks>
		[Ignore]
		[XmlIgnore]
		[DisplayName("Расширенная информация")]
		[Description("Необходима в случае хранения в программе дополнительной информации.")]
		[Category(_mainCategory)]
		public IDictionary<object, object> ExtensionInfo
		{
			get { return _extensionInfo; }
			set { _extensionInfo = value; }
		}

		private decimal _currentPrice;

		/// <summary>
		/// Стоимость позиции.
		/// </summary>
		[Ignore]
		[XmlIgnore]
		[DisplayName("Стоимость позиции")]
		[Description("Стоимость позиции, расчитанная по текущей рыночной цене инструмента.")]
		[Category(_mainCategory)]
		public decimal CurrentPrice
		{
			get { return _currentPrice; }
			set
			{
				if (_currentPrice == value)
					return;

				_currentPrice = value;
				Notify("CurrentPrice");
			}
		}

		private decimal _averagePrice;

		/// <summary>
		/// Средневзвешанная цена.
		/// </summary>
		[Ignore]
		[XmlIgnore]
		[DisplayName("Средневзвешанная цена")]
		[Description("Средневзвешанная цена, расчитанная по ценам исполнения.")]
		[Category(_mainCategory)]
		public decimal AveragePrice
		{
			get { return _averagePrice; }
			set
			{
				if (_averagePrice == value)
					return;

				_averagePrice = value;
				Notify("AveragePrice");
			}
		}

		private decimal _unrealizedPnL;

		/// <summary>
		/// Нереализованная прибыль.
		/// </summary>
		[Ignore]
		[XmlIgnore]
		[DisplayName("Нереализованная прибыль")]
		[Description("Нереализованная прибыль, расчитанная с учетом открытой позиции.")]
		[Category(_mainCategory)]
		public decimal UnrealizedPnL
		{
			get { return _unrealizedPnL; }
			set
			{
				if (_unrealizedPnL == value)
					return;

				_unrealizedPnL = value;
				Notify("UnrealizedPnL");
			}
		}

		private decimal _realizedPnL;

		/// <summary>
		/// Реализованная прибыль.
		/// </summary>
		[Ignore]
		[XmlIgnore]
		[DisplayName("Реализованная прибыль")]
		[Description("Реализованная прибыль, расчитанная по закрытым сделкам.")]
		[Category(_mainCategory)]
		public decimal RealizedPnL
		{
			get { return _realizedPnL; }
			set
			{
				if (_realizedPnL == value)
					return;

				_realizedPnL = value;
				Notify("RealizedPnL");
			}
		}

		/// <summary>
		/// Начать обновление данных. Окончание обновление данных инициируется через <see cref="UpdateTransaction.Dispose"/>.
		/// </summary>
		/// <returns>Транзакция на изменения данных.</returns>
		public UpdateTransaction BeginUpdate()
		{
			return _manager.BeginUpdate();
		}

		/// <summary>
		/// Начать чтение данных. В период действия транзакции потоки данных не могут изменить внутреннее состояние объекта, из которого читаются данные.
		/// Окончание чтения данных инициируется через <see cref="ReadTransaction.Dispose"/>.
		/// </summary>
		/// <param name="isUpgradable">Можно ли вызвать внутри блокировки на чтение внутреннюю блокировку на запись.</param>
		/// <returns>Транзакция на чтение данных.</returns>
		public ReadTransaction BeginRead(bool isUpgradable = false)
		{
			return _manager.BeginRead(isUpgradable);
		}

		/// <summary>
		/// Указать, что свойство обновлено.
		/// </summary>
		/// <param name="propName">Название свойства.</param>
		protected void Notify(string propName)
		{
			_manager.Do(() => NotifyPropertyChangedExHelper.Notify(this, propName));
		}
	}
}